package com.cencat.common.handler;

import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.cencat.common.utils.TenantUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.springframework.stereotype.Component;

import java.util.List;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 多租户SQL处理器
 * 自动在SQL中添加租户ID条件，实现数据隔离
 * 
 * @author cencat
 * @since 2024-01-01
 */
@Component
public class CencatTenantLineHandler implements TenantLineHandler {

    private static final Logger log = LoggerFactory.getLogger(CencatTenantLineHandler.class);

    /** 租户ID字段名 */
    private static final String TENANT_ID_COLUMN = "tenant_id";
    
    /** 忽略租户过滤的表名集合 */
    private static final Set<String> IGNORE_TENANT_TABLES = new HashSet<>(Arrays.asList(
        // 系统基础表（不需要租户隔离）
        "sys_tenant",           // 租户表本身
        "sys_dict_type",        // 字典类型表
        "sys_dict_data",        // 字典数据表
        "sys_config",           // 系统配置表
        "sys_operation_log",    // 操作日志表（全局）
        "sys_login_log",        // 登录日志表（全局）
        
        // 数据库系统表
        "information_schema",
        "performance_schema",
        "mysql",
        "sys",
        
        // 临时表和视图
        "temp_",
        "tmp_",
        "view_"
    ));
    
    /** 忽略租户过滤的SQL操作类型 */
    private static final Set<String> IGNORE_TENANT_OPERATIONS = new HashSet<>(Arrays.asList(
        "CREATE",
        "DROP",
        "ALTER",
        "TRUNCATE",
        "SHOW",
        "DESCRIBE",
        "EXPLAIN"
    ));

    /**
     * 获取租户ID值
     * 
     * @return 租户ID表达式
     */
    @Override
    public Expression getTenantId() {
        try {
            // 从TenantUtils获取Long类型的租户ID
            Long tenantId = com.cencat.common.utils.TenantUtils.getCurrentTenantId();
            
            if (tenantId == null || tenantId <= 0) {
                log.warn("当前租户ID为空或无效，可能导致数据访问异常");
                // 返回一个不存在的租户ID，确保数据安全
                return new net.sf.jsqlparser.expression.LongValue(-1L);
            }
            
            log.debug("获取当前租户ID: {}", tenantId);
            return new net.sf.jsqlparser.expression.LongValue(tenantId);
        } catch (Exception e) {
            log.error("获取租户ID失败: {}", e.getMessage());
            return new net.sf.jsqlparser.expression.LongValue(-1L);
        }
    }

    /**
     * 获取租户字段名
     * 
     * @return 租户字段名
     */
    @Override
    public String getTenantIdColumn() {
        return TENANT_ID_COLUMN;
    }

    /**
     * 根据表名判断是否忽略拼接多租户条件
     * 
     * @param tableName 表名
     * @return true-忽略，false-不忽略
     */
    @Override
    public boolean ignoreTable(String tableName) {
        if (tableName == null || tableName.trim().isEmpty()) {
            return true;
        }
        
        // 转换为小写进行比较
        String lowerTableName = tableName.toLowerCase();
        
        // 检查是否在忽略列表中
        boolean shouldIgnore = IGNORE_TENANT_TABLES.stream()
            .anyMatch(ignoreTable -> lowerTableName.equals(ignoreTable) || lowerTableName.startsWith(ignoreTable));
        
        if (shouldIgnore) {
            log.debug("表 {} 被忽略多租户过滤", tableName);
        } else {
            log.debug("表 {} 将应用多租户过滤", tableName);
        }
        
        return shouldIgnore;
    }

    /**
     * 判断是否忽略租户过滤（基于SQL类型）
     * 
     * @param sql SQL语句
     * @return true-忽略，false-不忽略
     */
    public boolean ignoreByOperation(String sql) {
        if (sql == null || sql.trim().isEmpty()) {
            return true;
        }
        
        String upperSql = sql.trim().toUpperCase();
        
        // 检查是否为忽略的操作类型
        boolean shouldIgnore = IGNORE_TENANT_OPERATIONS.stream()
            .anyMatch(upperSql::startsWith);
        
        if (shouldIgnore) {
            log.debug("SQL操作被忽略多租户过滤: {}", sql.substring(0, Math.min(50, sql.length())));
        }
        
        return shouldIgnore;
    }

    /**
     * 检查当前是否需要应用租户过滤
     * 
     * @return true-需要，false-不需要
     */
    public boolean shouldApplyTenantFilter() {
        try {
            // 检查是否在租户上下文中
            Long tenantId = com.cencat.common.utils.TenantUtils.getCurrentTenantId();
            if (tenantId == null || tenantId <= 0) {
                log.debug("租户ID为空或无效，跳过租户过滤");
                return false;
            }
            
            // 检查是否为超级管理员（可以访问所有租户数据）
            if (com.cencat.common.utils.TenantUtils.isSuperAdmin()) {
                log.debug("当前用户为超级管理员，跳过租户过滤");
                return false;
            }
            
            // 检查是否临时忽略租户过滤
            if (com.cencat.common.utils.TenantUtils.isIgnoreTenant()) {
                log.debug("临时忽略租户过滤");
                return false;
            }
            
            return true;
        } catch (Exception e) {
            log.error("检查租户过滤条件失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 添加忽略表名
     * 
     * @param tableName 表名
     */
    public static void addIgnoreTable(String tableName) {
        if (tableName != null && !tableName.trim().isEmpty()) {
            IGNORE_TENANT_TABLES.add(tableName.toLowerCase());
            log.info("添加忽略租户过滤的表: {}", tableName);
        }
    }

    /**
     * 移除忽略表名
     * 
     * @param tableName 表名
     */
    public static void removeIgnoreTable(String tableName) {
        if (tableName != null && !tableName.trim().isEmpty()) {
            IGNORE_TENANT_TABLES.remove(tableName.toLowerCase());
            log.info("移除忽略租户过滤的表: {}", tableName);
        }
    }

    /**
     * 获取所有忽略的表名
     * 
     * @return 忽略的表名集合
     */
    public static Set<String> getIgnoreTables() {
        return new HashSet<>(IGNORE_TENANT_TABLES);
    }

    /**
     * 清空忽略表名配置
     */
    public static void clearIgnoreTables() {
        IGNORE_TENANT_TABLES.clear();
        log.warn("已清空所有忽略租户过滤的表配置");
    }

    /**
     * 租户过滤配置
     */
    public static class TenantFilterConfig {
        /** 是否启用租户过滤 */
        private boolean enabled = true;
        
        /** 租户ID字段名 */
        private String tenantIdColumn = TENANT_ID_COLUMN;
        
        /** 默认租户ID */
        private String defaultTenantId;
        
        /** 是否严格模式（租户ID为空时抛异常） */
        private boolean strictMode = false;
        
        /** 是否记录SQL日志 */
        private boolean logSql = false;

        // Getters and Setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) { this.enabled = enabled; }
        public String getTenantIdColumn() { return tenantIdColumn; }
        public void setTenantIdColumn(String tenantIdColumn) { this.tenantIdColumn = tenantIdColumn; }
        public String getDefaultTenantId() { return defaultTenantId; }
        public void setDefaultTenantId(String defaultTenantId) { this.defaultTenantId = defaultTenantId; }
        public boolean isStrictMode() { return strictMode; }
        public void setStrictMode(boolean strictMode) { this.strictMode = strictMode; }
        public boolean isLogSql() { return logSql; }
        public void setLogSql(boolean logSql) { this.logSql = logSql; }
    }

    /**
     * 租户过滤统计信息
     */
    public static class TenantFilterStats {
        /** 总SQL执行次数 */
        private long totalSqlCount = 0;
        
        /** 应用租户过滤的SQL次数 */
        private long filteredSqlCount = 0;
        
        /** 忽略租户过滤的SQL次数 */
        private long ignoredSqlCount = 0;
        
        /** 最后更新时间 */
        private java.time.LocalDateTime lastUpdateTime;

        // Getters and Setters
        public long getTotalSqlCount() { return totalSqlCount; }
        public void setTotalSqlCount(long totalSqlCount) { this.totalSqlCount = totalSqlCount; }
        public long getFilteredSqlCount() { return filteredSqlCount; }
        public void setFilteredSqlCount(long filteredSqlCount) { this.filteredSqlCount = filteredSqlCount; }
        public long getIgnoredSqlCount() { return ignoredSqlCount; }
        public void setIgnoredSqlCount(long ignoredSqlCount) { this.ignoredSqlCount = ignoredSqlCount; }
        public java.time.LocalDateTime getLastUpdateTime() { return lastUpdateTime; }
        public void setLastUpdateTime(java.time.LocalDateTime lastUpdateTime) { this.lastUpdateTime = lastUpdateTime; }
        
        /**
         * 增加总SQL计数
         */
        public void incrementTotalSql() {
            this.totalSqlCount++;
            this.lastUpdateTime = java.time.LocalDateTime.now();
        }
        
        /**
         * 增加过滤SQL计数
         */
        public void incrementFilteredSql() {
            this.filteredSqlCount++;
            this.lastUpdateTime = java.time.LocalDateTime.now();
        }
        
        /**
         * 增加忽略SQL计数
         */
        public void incrementIgnoredSql() {
            this.ignoredSqlCount++;
            this.lastUpdateTime = java.time.LocalDateTime.now();
        }
        
        /**
         * 重置统计信息
         */
        public void reset() {
            this.totalSqlCount = 0;
            this.filteredSqlCount = 0;
            this.ignoredSqlCount = 0;
            this.lastUpdateTime = java.time.LocalDateTime.now();
        }
    }
}